/**
 * @brief MCU SRAM/PSRAM/NOR 驱动
 * @author 张勇 41204@qq.com
 * @date 2022-04
 */

#include "mcu.h"
#include "_mcu_sram_nor.h"

// FMC-SRAM/PSRAM/NOR 引脚初始化
void _sram_nor_gpio_init(mcu_sram_nor_t *sram) {
    GPIO_InitTypeDef gpio_init_struct;    
    gpio_init_struct.Mode = GPIO_MODE_AF_PP;     // 推挽复用
    gpio_init_struct.Pull = GPIO_PULLUP;         // 上拉
    gpio_init_struct.Speed = GPIO_SPEED_HIGH;    // 高速
    gpio_init_struct.Alternate = GPIO_AF12_FMC;  // 复用为 FMC

    // 初始化 FMC@GPIOB:    NADV
    gpio_init_struct.Pin = GPIO_PIN_7;
    HAL_GPIO_Init(GPIOB, &gpio_init_struct);
    
    // 初始化 FMC@GPIOD:    D2           D3           CLK           NOE           NWE           NWAIT         A16           A17           A18           D0            D1
    gpio_init_struct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3  | GPIO_PIN_4  | GPIO_PIN_5  | GPIO_PIN_6  | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
    HAL_GPIO_Init(GPIOD, &gpio_init_struct);
    
    // 初始化 FMC@GPIOE:    NBL0         NBL1         A23           A19           A20           A21           A22           D4            D5            D6            D7         
    gpio_init_struct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2  | GPIO_PIN_3  | GPIO_PIN_4  | GPIO_PIN_5  | GPIO_PIN_6  | GPIO_PIN_7  | GPIO_PIN_8  | GPIO_PIN_9  | GPIO_PIN_10;
    HAL_GPIO_Init(GPIOE, &gpio_init_struct);                     
                                                                 
    // 初始化 FMC@GPIOF:    A0           A1           A2            A3            A4            A5            A6            A7            A8            A9
    gpio_init_struct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2  | GPIO_PIN_3  | GPIO_PIN_4  | GPIO_PIN_5  | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
    HAL_GPIO_Init(GPIOF, &gpio_init_struct);                     
                                                                 
    // 初始化 FMC@GPIOG:    A10          A11          A12           A13           A14           A15           A24            A25
    gpio_init_struct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2  | GPIO_PIN_3  | GPIO_PIN_4  | GPIO_PIN_5  | GPIO_PIN_13 | GPIO_PIN_14;
    HAL_GPIO_Init(GPIOG, &gpio_init_struct);
    
    if(sram->hsram.Init.MemoryDataWidth >= FMC_NORSRAM_MEM_BUS_WIDTH_16) {
        // 初始化 FMC@GPIOE:    NBL0         NBL1         D8            D9            D10           D11           D12
        gpio_init_struct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
        HAL_GPIO_Init(GPIOE, &gpio_init_struct);
        // 初始化 FMC@GPIOD:    D13          D14          D15        
        gpio_init_struct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
        HAL_GPIO_Init(GPIOD, &gpio_init_struct);
    }
    if(sram->hsram.Init.MemoryDataWidth >= FMC_NORSRAM_MEM_BUS_WIDTH_32) {
        // 初始化 FMC@GPIOH:    D16          D17          D18           D19           D20           D21           D22           D23
        gpio_init_struct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
        HAL_GPIO_Init(GPIOH, &gpio_init_struct);
        // 初始化 FMC@GPIOI:    D24          D25          D26           D27           NBL2          NBL3          D28           D29          D30          D31
        gpio_init_struct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2  | GPIO_PIN_3  | GPIO_PIN_4  | GPIO_PIN_5  | GPIO_PIN_6  | GPIO_PIN_7 | GPIO_PIN_9 | GPIO_PIN_10;
        HAL_GPIO_Init(GPIOI, &gpio_init_struct);
    }
    
    // 初始化 FMC: NE
    if(sram->hsram.Init.NSBank == FMC_NORSRAM_BANK1) { gpio_init_struct.Pin = GPIO_PIN_7;  HAL_GPIO_Init(GPIOD, &gpio_init_struct); } // NE1
    if(sram->hsram.Init.NSBank == FMC_NORSRAM_BANK2) { gpio_init_struct.Pin = GPIO_PIN_9;  HAL_GPIO_Init(GPIOG, &gpio_init_struct); } // NE2
    if(sram->hsram.Init.NSBank == FMC_NORSRAM_BANK3) { gpio_init_struct.Pin = GPIO_PIN_10; HAL_GPIO_Init(GPIOG, &gpio_init_struct); } // NE3
    if(sram->hsram.Init.NSBank == FMC_NORSRAM_BANK4) { gpio_init_struct.Pin = GPIO_PIN_12; HAL_GPIO_Init(GPIOG, &gpio_init_struct); } // NE4
}

std_err_t mcu_sram_nor_init(mcu_sram_nor_t *sram) {
    HAL_StatusTypeDef ret;
    
	// FMC-SDRAM 引脚初始化
    _sram_nor_gpio_init(sram);
    
    // 设置 时序参数
    ret = HAL_SRAM_Init(&sram->hsram, &sram->timing, NULL); if(ret != HAL_OK) return STD_ERR_FAIL;
    
    // 测试
    return mcu_sram_nor_test(sram);
}

std_err_t mcu_sram_nor_test(mcu_sram_nor_t *sram) {
    uint32_t i, temp = 0, sval = 0;

    // 每隔 16K 字节, 写入一个数据
    for (i = 0; i < sram->size; i += 16 * 1024) {
        *(volatile uint32_t *)(sram->base_addr + i) = temp; 
        temp++;
    }

    // 依次读出之前写入的数据进行校验
    for (i = 0; i < sram->size; i += 16 * 1024) {
        temp =*(volatile uint32_t*)(sram->base_addr + i);
        if(temp != sval) return STD_ERR_FAIL;
        sval++;
    }
    return STD_ERR_OK;
}
